/*ES6 规定， Promise对象是一个构造函数， 用来生成Promise实例。
下面代码创造了一个Promise实例。
Promise构造函数接受一个函数作为参数，该函数的两个参数分别是resolve和reject。它们是两个函数，
由 JavaScript 引擎提供，不用自己部署。
*/
const promise = new Promise(function(resolve, reject) {
	// ... some code

	if ( /* 异步操作成功 */ ) {
		resolve(value);
	} else {
		reject(error);
	}
});

/*
resolve函数的作用是，将Promise对象的状态从“未完成”变为“成功”（即从 pending 变为 resolved），
在异步操作成功时调用，并将异步操作的结果，作为参数传递出去；
reject函数的作用是，将Promise对象的状态从“未完成”变为“失败”（即从 pending 变为 rejected），
在异步操作失败时调用，并将异步操作报出的错误，作为参数传递出去。
*/


//Promise实例生成以后，可以用then方法分别指定resolved状态和rejected状态的回调函数。
promise.then(function(value) {
	// success
}, function(error) {
	// failure
});



//下面是一个Promise对象的简单例子。
function timeout(ms) {
	return new Promise((resolve, reject) => {
		setTimeout(resolve, ms, 'done'); //后面的参数作为第一个回调函数的参数
	});
}
timeout(100).then((value) => {
	console.log(value);
});



//Promise 新建后就会立即执行。
let promise = new Promise(function(resolve, reject) {
	console.log('Promise');
	resolve();
});
promise.then(function() { //要等到同步执行完毕再执行异步
	console.log('resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// resolved



//下面是异步加载图片的例子。
function loadImageAsync(url) {
	return new Promise(function(resolve, reject) {
		const image = new Image();

		image.onload = function() {
			resolve(image);
		};

		image.onerror = function() {
			reject(new Error('Could not load image at ' + url));
		};

		image.src = url;
	});
}



//下面是一个用Promise对象实现的 Ajax 操作的例子。
const getJSON = function(url) {
	const promise = new Promise(function(resolve, reject) {
		const handler = function() {
			if (this.readyState !== 4) {
				return;
			}
			if (this.status === 200) {
				resolve(this.response);
			} else {
				reject(new Error(this.statusText));
			}
		};
		const client = new XMLHttpRequest();
		client.open("GET", url);
		client.onreadystatechange = handler;
		client.responseType = "json";
		client.setRequestHeader("Accept", "application/json");
		client.send();
	});

	return promise;
};
getJSON("/posts.json").then(function(json) {
	console.log('Contents: ' + json);
}, function(error) {
	console.error('出错了', error);
});




/*如果调用resolve函数和reject函数时带有参数，那么它们的参数会被传递给回调函数。
reject函数的参数通常是Error对象的实例，表示抛出的错误；
resolve函数的参数除了正常的值以外，还可能是另一个 Promise 实例，比如像下面这样。
*/
const p1 = new Promise(function(resolve, reject) {
	// ...
});
const p2 = new Promise(function(resolve, reject) {
	// ...
	resolve(p1);
})



/*
p1是一个 Promise，3 秒之后变为rejected。
p2的状态在 1 秒之后改变，resolve方法返回的是p1。
由于p2返回的是另一个 Promise，导致p2自己的状态无效了，由p1的状态决定p2的状态。
所以，后面的then语句都变成针对后者（p1）。
又过了 2 秒，p1变为rejected，导致触发catch方法指定的回调函数
*/
const p1 = new Promise(function(resolve, reject) {
	setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function(resolve, reject) {
	setTimeout(() => resolve(p1), 1000) //当参数也为promise对象时 会覆盖上一个promise对象
})
p2.then(result => console.log(result)).catch(error => console.log(error))
// Error: fail



/*注意，调用resolve或reject并不会终结 Promise 的参数函数的执行。
这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行，总是晚于本轮循环的同步任务。
所以养成把状态回调当成return写的习惯，resolve, reject总是在最后书写
*/
new Promise((resolve, reject) => {
	resolve(1);
	console.log(2);
}).then(r => {
	console.log(r);
});
// 2
// 1
//如果实在想打断后续同步代码就在前面加上return
new Promise((resolve, reject) => {
	return resolve(1);
	// 后面的语句不会执行
	console.log(2);
})
